Revamp and modernize X error traps
authorHavoc Pennington <hp@pobox.com>
Sat, 18 Sep 2010 22:19:27 +0000 (18:19 -0400)
committerMatthias Clasen <mclasen@redhat.com>
Sat, 18 Sep 2010 22:19:27 +0000 (18:19 -0400)
* add per-display gdk_x11_display_error_trap_push()
  (X11-specific because gdk_error_trap_push() probably
  should have been)
* make gdk_error_trap_push() handle only GDK displays
  not displays opened without a GDK wrapper
* make gdk_error_trap_pop() and gdk_x11_display_error_trap_pop()
  automatically sync only if needed, so manual gdk_flush() is not
  required
* add gdk_error_trap_pop_ignored() which just asynchronously
  ignores errors, so never needs to sync
* add G_GNUC_WARN_UNUSED_RESULT to plain pop(), because
  if you use plain pop() and don't need the return value,
  the async gdk_error_trap_pop_ignored() should be used
  instead. This results in lots of warnings to clean
  up in a later patch.

The main objective here was to avoid the need to sync just
to ignore an error. Now, syncing is automatic, and only
happens when we need to know the error code.

https://bugzilla.gnome.org/show_bug.cgi?id=629608

docs/reference/gdk/tmpl/general.sgml
gdk/gdk.h
gdk/gdkglobals.c
gdk/gdkinternals.h
gdk/quartz/gdkmain-quartz.c
gdk/win32/gdkmain-win32.c
gdk/x11/gdkdisplay-x11.c
gdk/x11/gdkdisplay-x11.h
gdk/x11/gdkmain-x11.c
gdk/x11/gdkprivate-x11.h
gdk/x11/gdkx.h

index a2aaf3d71146d4af7ed855a6f97e28ec7609aff2..1b8080b78f39cb126d9a20491080e8ae31d97ac6 100644 (file)
@@ -326,42 +326,6 @@ available.
 
 @void: 
 
-
-<!-- ##### FUNCTION gdk_error_trap_push ##### -->
-<para>
-This function allows X errors to be trapped instead of the normal behavior
-of exiting the application. It should only be used if it is not possible to
-avoid the X error in any other way.
-</para>
-<example>
-<title>Trapping an X error</title>
-<programlisting>
-  gdk_error_trap_push (<!-- -->);
-
-  /* ... Call the X function which may cause an error here ... */
-
-  /* Flush the X queue to catch errors now. */
-  gdk_flush (<!-- -->);
-
-  if (gdk_error_trap_pop (<!-- -->))
-    {
-      /* ... Handle the error here ... */
-    }
-</programlisting>
-</example>
-
-@void: 
-
-
-<!-- ##### FUNCTION gdk_error_trap_pop ##### -->
-<para>
-Removes the X error trap installed with gdk_error_trap_push().
-</para>
-
-@void: 
-@Returns: the X error code, or 0 if no error occurred.
-
-
 <!-- ##### MACRO GDK_WINDOWING_X11 ##### -->
 <para>
 This macro is defined if GDK is configured to use the X11 backend.
index a6c7578a80bf023e1d84f46a352cdc421295f4e5..ea7926a86db80434c28e94e7754a322858a91410 100644 (file)
--- a/gdk/gdk.h
+++ b/gdk/gdk.h
@@ -81,8 +81,11 @@ void                 gdk_set_program_class (const char *program_class);
 
 /* Push and pop error handlers for X errors
  */
-void      gdk_error_trap_push           (void);
-gint      gdk_error_trap_pop            (void);
+void                           gdk_error_trap_push        (void);
+/* warn unused because you could use pop_ignored otherwise */
+G_GNUC_WARN_UNUSED_RESULT gint gdk_error_trap_pop         (void);
+void                           gdk_error_trap_pop_ignored (void);
+
 
 gchar*                   gdk_get_display               (void);
 G_CONST_RETURN gchar*    gdk_get_display_arg_name      (void);
index b9d86e137d7a9e81d9551747bec3b5298df30d24..fc734958729f28678e56e76a6fef2ae3ce5abce0 100644 (file)
@@ -33,8 +33,6 @@
 
 
 guint               _gdk_debug_flags = 0;
-gint                _gdk_error_code = 0;
-gint                _gdk_error_warnings = TRUE;
 GList              *_gdk_default_filters = NULL;
 gchar              *_gdk_display_name = NULL;
 gint                _gdk_screen_number = -1;
index 4f4aa1d07c76c8d095564c7831c6e26ecd919955..7740bce66dd0a4d83a940b10fa9f831ede5c8f93 100644 (file)
@@ -88,8 +88,6 @@ typedef enum {
 
 extern GList            *_gdk_default_filters;
 extern GdkWindow       *_gdk_parent_root;
-extern gint             _gdk_error_code;
-extern gint             _gdk_error_warnings;
 
 extern guint _gdk_debug_flags;
 extern gboolean _gdk_native_windows;
index af765d02b1ae7b64b86d21e2bac333b047d10b6d..6e84756907a3f74104996e0ae37e4d3c41d2a810 100644 (file)
@@ -56,6 +56,11 @@ gdk_error_trap_pop (void)
   return 0;
 }
 
+void
+gdk_error_trap_pop_ignored (void)
+{
+}
+
 gchar *
 gdk_get_display (void)
 {
index 02ab4eab3177ef1a5c831fec177c54869137cd9f..cc8c6fcad8f5633d33404fc67725baabddcdc056 100644 (file)
@@ -214,6 +214,11 @@ gdk_error_trap_pop (void)
   return 0;
 }
 
+void
+gdk_error_trap_pop_ignored (void)
+{
+}
+
 void
 gdk_notify_startup_complete (void)
 {
index 31f9ec12d7f33ff2f12d9e0d81880a15a4e5b80f..9ad4178007e82909b9abb9155fbcd2ec15c42944 100644 (file)
@@ -24,6 +24,7 @@
 
 #include "config.h"
 
+#include <glib/gprintf.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
 #include <X11/extensions/Xrandr.h>
 #endif
 
+typedef struct _GdkErrorTrap  GdkErrorTrap;
+
+struct _GdkErrorTrap
+{
+  /* Next sequence when trap was pushed, i.e. first sequence to
+   * ignore
+   */
+  gulong start_sequence;
+
+  /* Next sequence when trap was popped, i.e. first sequence
+   * to not ignore. 0 if trap is still active.
+   */
+  gulong end_sequence;
+
+  /* Most recent error code within the sequence */
+  int error_code;
+};
 
 static void   gdk_display_x11_dispose            (GObject            *object);
 static void   gdk_display_x11_finalize           (GObject            *object);
@@ -2657,3 +2675,250 @@ gdk_x11_register_standard_event_type (GdkDisplay *display,
 
   display_x11->event_types = g_slist_prepend (display_x11->event_types, event_type);
 }
+
+/* compare X sequence numbers handling wraparound */
+#define SEQUENCE_COMPARE(a,op,b) (((long) (a) - (long) (b)) op 0)
+
+/* delivers an error event from the error handler in gdkmain-x11.c */
+void
+_gdk_x11_display_error_event (GdkDisplay  *display,
+                              XErrorEvent *error)
+{
+  GdkDisplayX11 *display_x11;
+  GSList *tmp_list;
+  gboolean ignore;
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  ignore = FALSE;
+  for (tmp_list = display_x11->error_traps;
+       tmp_list != NULL;
+       tmp_list = tmp_list->next)
+    {
+      GdkErrorTrap *trap;
+
+      trap = tmp_list->data;
+
+      if (SEQUENCE_COMPARE (trap->start_sequence, <=, error->serial) &&
+          (trap->end_sequence == 0 ||
+           SEQUENCE_COMPARE (trap->end_sequence, >, error->serial)))
+        {
+          ignore = TRUE;
+          trap->error_code = error->error_code;
+        }
+    }
+
+  if (!ignore)
+    {
+      gchar buf[64];
+      gchar *msg;
+
+      XGetErrorText (display_x11->xdisplay, error->error_code, buf, 63);
+
+      msg =
+        g_strdup_printf ("The program '%s' received an X Window System error.\n"
+                         "This probably reflects a bug in the program.\n"
+                         "The error was '%s'.\n"
+                         "  (Details: serial %ld error_code %d request_code %d minor_code %d)\n"
+                         "  (Note to programmers: normally, X errors are reported asynchronously;\n"
+                         "   that is, you will receive the error a while after causing it.\n"
+                         "   To debug your program, run it with the --sync command line\n"
+                         "   option to change this behavior. You can then get a meaningful\n"
+                         "   backtrace from your debugger if you break on the gdk_x_error() function.)",
+                         g_get_prgname (),
+                         buf,
+                         error->serial,
+                         error->error_code,
+                         error->request_code,
+                         error->minor_code);
+
+#ifdef G_ENABLE_DEBUG
+      g_error ("%s", msg);
+#else /* !G_ENABLE_DEBUG */
+      g_fprintf (stderr, "%s\n", msg);
+
+      exit (1);
+#endif /* G_ENABLE_DEBUG */
+    }
+}
+
+static void
+delete_outdated_error_traps (GdkDisplayX11 *display_x11)
+{
+  GSList *tmp_list;
+  gulong processed_sequence;
+
+  processed_sequence = XLastKnownRequestProcessed (display_x11->xdisplay);
+
+  tmp_list = display_x11->error_traps;
+  while (tmp_list != NULL)
+    {
+      GdkErrorTrap *trap = tmp_list->data;
+
+      if (trap->end_sequence != 0 &&
+          SEQUENCE_COMPARE (trap->end_sequence, <, processed_sequence))
+        {
+          GSList *free_me = tmp_list;
+
+          tmp_list = tmp_list->next;
+          display_x11->error_traps =
+            g_slist_delete_link (display_x11->error_traps, free_me);
+          g_slice_free (GdkErrorTrap, trap);
+        }
+      else
+        {
+          tmp_list = tmp_list->next;
+        }
+    }
+}
+
+/**
+ * gdk_x11_display_error_trap_push:
+ *
+ * Begins a range of X requests for which X error events will be
+ * ignored. Unignored errors (when no trap is pushed) will abort the
+ * application.
+ *
+ * See also gdk_error_trap_push() to push a trap on all displays.
+ *
+ * Since: 3.0
+ */
+void
+gdk_x11_display_error_trap_push (GdkDisplay *display)
+{
+  GdkDisplayX11 *display_x11;
+  GdkErrorTrap *trap;
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  delete_outdated_error_traps (display_x11);
+
+  /* set up the Xlib callback to tell us about errors */
+  _gdk_x11_error_handler_push ();
+
+  trap = g_slice_new0 (GdkErrorTrap);
+
+  trap->start_sequence = XNextRequest (display_x11->xdisplay);
+  trap->error_code = Success;
+
+  display_x11->error_traps =
+    g_slist_prepend (display_x11->error_traps, trap);
+}
+
+static gint
+gdk_x11_display_error_trap_pop_internal (GdkDisplay *display,
+                                         gboolean    need_code)
+{
+  GdkDisplayX11 *display_x11;
+  GdkErrorTrap *trap;
+  GSList *tmp_list;
+  int result;
+
+  display_x11 = GDK_DISPLAY_X11 (display);
+
+  g_return_val_if_fail (display_x11->error_traps != NULL, Success);
+
+  /* Find the first trap that hasn't been popped already */
+  trap = NULL; /* quiet gcc */
+  for (tmp_list = display_x11->error_traps;
+       tmp_list != NULL;
+       tmp_list = tmp_list->next)
+    {
+      trap = tmp_list->data;
+
+      if (trap->end_sequence == 0)
+        break;
+    }
+
+  g_return_val_if_fail (trap != NULL, Success);
+  g_assert (trap->end_sequence == 0);
+
+  /* May need to sync to fill in trap->error_code if we care about
+   * getting an error code.
+   */
+  if (need_code)
+    {
+      gulong processed_sequence;
+      gulong next_sequence;
+
+      next_sequence = XNextRequest (display_x11->xdisplay);
+      processed_sequence = XLastKnownRequestProcessed (display_x11->xdisplay);
+
+      /* If our last request was already processed, there is no point
+       * in syncing. i.e. if last request was a round trip (or even if
+       * we got an event with the serial of a non-round-trip)
+       */
+      if ((next_sequence - 1) != processed_sequence)
+        {
+          XSync (display_x11->xdisplay, False);
+        }
+
+      result = trap->error_code;
+    }
+  else
+    {
+      result = Success;
+    }
+
+  /* record end of trap, giving us a range of
+   * error sequences we'll ignore.
+   */
+  trap->end_sequence = XNextRequest (display_x11->xdisplay);
+
+  /* remove the Xlib callback */
+  _gdk_x11_error_handler_pop ();
+
+  /* we may already be outdated */
+  delete_outdated_error_traps (display_x11);
+
+  return result;
+}
+
+/**
+ * gdk_x11_display_error_trap_pop:
+ * @display: the display
+ *
+ * Pops the error trap pushed by gdk_x11_display_error_trap_push().
+ * Will XSync() if necessary and will always block until
+ * the error is known to have occurred or not occurred,
+ * so the error code can be returned.
+ *
+ * If you don't need to use the return value,
+ * gdk_x11_display_error_trap_pop_ignored() would be more efficient.
+ *
+ * See gdk_error_trap_pop() for the all-displays-at-once
+ * equivalent.
+ *
+ * Since: 3.0
+ *
+ * Return value: X error code or 0 on success
+ */
+gint
+gdk_x11_display_error_trap_pop (GdkDisplay *display)
+{
+  g_return_val_if_fail (GDK_IS_DISPLAY_X11 (display), Success);
+
+  return gdk_x11_display_error_trap_pop_internal (display, TRUE);
+}
+
+/**
+ * gdk_x11_display_error_trap_pop_ignored:
+ * @display: the display
+ *
+ * Pops the error trap pushed by gdk_x11_display_error_trap_push().
+ * Does not block to see if an error occurred; merely records the
+ * range of requests to ignore errors for, and ignores those errors
+ * if they arrive asynchronously.
+ *
+ * See gdk_error_trap_pop_ignored() for the all-displays-at-once
+ * equivalent.
+ *
+ * Since: 3.0
+ */
+void
+gdk_x11_display_error_trap_pop_ignored (GdkDisplay *display)
+{
+  g_return_if_fail (GDK_IS_DISPLAY_X11 (display));
+
+  gdk_x11_display_error_trap_pop_internal (display, FALSE);
+}
index 87496d4321b0d6584b8b112257cb66b1f93bdaca..b4036cb59131462bc4bb5686215b159f54109332 100644 (file)
@@ -141,6 +141,8 @@ struct _GdkDisplayX11
 
   /* The offscreen window that has the pointer in it (if any) */
   GdkWindow *active_offscreen_window;
+
+  GSList *error_traps;
 };
 
 struct _GdkDisplayX11Class
@@ -149,8 +151,10 @@ struct _GdkDisplayX11Class
 };
 
 GType      _gdk_display_x11_get_type            (void);
-GdkScreen *_gdk_x11_display_screen_for_xrootwin (GdkDisplay *display,
-                                                Window      xrootwin);
+GdkScreen *_gdk_x11_display_screen_for_xrootwin (GdkDisplay  *display,
+                                                Window       xrootwin);
+void       _gdk_x11_display_error_event         (GdkDisplay  *display,
+                                                 XErrorEvent *error);
 
 G_END_DECLS
 
index 238c52ecc6282cfe550109f4f27e64de7c4cd7b1..996715c75fce572b9726dec9a2166d785b147aba 100644 (file)
@@ -52,8 +52,8 @@
 
 #include <gdk/gdkdeviceprivate.h>
 
-typedef struct _GdkPredicate  GdkPredicate;
-typedef struct _GdkErrorTrap  GdkErrorTrap;
+typedef struct _GdkPredicate        GdkPredicate;
+typedef struct _GdkGlobalErrorTrap  GdkGlobalErrorTrap;
 
 struct _GdkPredicate
 {
@@ -61,11 +61,14 @@ struct _GdkPredicate
   gpointer data;
 };
 
-struct _GdkErrorTrap
+/* non-GDK previous error handler */
+static int (*_gdk_old_error_handler) (Display *, XErrorEvent *);
+/* number of times we've pushed the GDK error handler */
+static int _gdk_error_handler_push_count = 0;
+
+struct _GdkGlobalErrorTrap
 {
-  int (*old_handler) (Display *, XErrorEvent *);
-  gint error_warnings;
-  gint error_code;
+  GSList *displays;
 };
 
 /* 
@@ -284,72 +287,6 @@ _gdk_windowing_exit (void)
   }
 }
 
-/*
- *--------------------------------------------------------------
- * gdk_x_error
- *
- *   The X error handling routine.
- *
- * Arguments:
- *   "display" is the X display the error originated from.
- *   "error" is the XErrorEvent that we are handling.
- *
- * Results:
- *   Either we were expecting some sort of error to occur,
- *   in which case we set the "_gdk_error_code" flag, or this
- *   error was unexpected, in which case we will print an
- *   error message and exit. (Since trying to continue will
- *   most likely simply lead to more errors).
- *
- * Side effects:
- *
- *--------------------------------------------------------------
- */
-
-static int
-gdk_x_error (Display    *display,
-            XErrorEvent *error)
-{
-  if (error->error_code)
-    {
-      if (_gdk_error_warnings)
-       {
-         gchar buf[64];
-          gchar *msg;
-
-         XGetErrorText (display, error->error_code, buf, 63);
-
-          msg =
-            g_strdup_printf ("The program '%s' received an X Window System error.\n"
-                             "This probably reflects a bug in the program.\n"
-                             "The error was '%s'.\n"
-                             "  (Details: serial %ld error_code %d request_code %d minor_code %d)\n"
-                             "  (Note to programmers: normally, X errors are reported asynchronously;\n"
-                             "   that is, you will receive the error a while after causing it.\n"
-                             "   To debug your program, run it with the --sync command line\n"
-                             "   option to change this behavior. You can then get a meaningful\n"
-                             "   backtrace from your debugger if you break on the gdk_x_error() function.)",
-                             g_get_prgname (),
-                             buf,
-                             error->serial,
-                             error->error_code,
-                             error->request_code,
-                             error->minor_code);
-
-#ifdef G_ENABLE_DEBUG
-         g_error ("%s", msg);
-#else /* !G_ENABLE_DEBUG */
-         g_fprintf (stderr, "%s\n", msg);
-
-         exit (1);
-#endif /* G_ENABLE_DEBUG */
-       }
-      _gdk_error_code = error->error_code;
-    }
-
-  return 0;
-}
-
 /*
  *--------------------------------------------------------------
  * gdk_x_io_error
@@ -398,43 +335,212 @@ gdk_x_io_error (Display *display)
   exit(1);
 }
 
+/* X error handler. Keep the name the same because people are used to
+ * breaking on it in the debugger.
+ */
+static int
+gdk_x_error (Display    *xdisplay,
+            XErrorEvent *error)
+{
+  if (error->error_code)
+    {
+      GdkDisplay *error_display;
+      GdkDisplayManager *manager;
+      GSList *displays;
+
+      /* Figure out which GdkDisplay if any got the error. */
+      error_display = NULL;
+      manager = gdk_display_manager_get ();
+      displays = gdk_display_manager_list_displays (manager);
+      while (displays != NULL)
+        {
+          GdkDisplayX11 *gdk_display = displays->data;
+
+          if (xdisplay == gdk_display->xdisplay)
+            {
+              error_display = GDK_DISPLAY_OBJECT (gdk_display);
+              g_slist_free (displays);
+              displays = NULL;
+            }
+          else
+            {
+              displays = g_slist_delete_link (displays, displays);
+            }
+        }
+
+      if (error_display == NULL)
+        {
+          /* Error on an X display not opened by GDK. Ignore. */
+
+          return 0;
+        }
+      else
+        {
+          _gdk_x11_display_error_event (error_display, error);
+        }
+    }
+
+  return 0;
+}
+
 void
-gdk_error_trap_push (void)
+_gdk_x11_error_handler_push (void)
 {
-  GdkErrorTrap *trap;
+  _gdk_old_error_handler = XSetErrorHandler (gdk_x_error);
 
-  trap = g_slice_new (GdkErrorTrap);
+  if (_gdk_error_handler_push_count > 0)
+    {
+      if (_gdk_old_error_handler != gdk_x_error)
+        g_warning ("XSetErrorHandler() called with a GDK error trap pushed. Don't do that.");
+    }
 
-  trap->old_handler = XSetErrorHandler (gdk_x_error);
-  trap->error_code = _gdk_error_code;
-  trap->error_warnings = _gdk_error_warnings;
+  _gdk_error_handler_push_count += 1;
+}
+
+void
+_gdk_x11_error_handler_pop  (void)
+{
+  g_return_if_fail (_gdk_error_handler_push_count > 0);
+
+  _gdk_error_handler_push_count -= 1;
+
+  if (_gdk_error_handler_push_count == 0)
+    {
+      XSetErrorHandler (_gdk_old_error_handler);
+      _gdk_old_error_handler = NULL;
+    }
+}
+
+/**
+ * gdk_error_trap_push:
+ *
+ * This function allows X errors to be trapped instead of the normal
+ * behavior of exiting the application. It should only be used if it
+ * is not possible to avoid the X error in any other way. Errors are
+ * ignored on all #GdkDisplay currently known to the
+ * #GdkDisplayManager. If you don't care which error happens and just
+ * want to ignore everything, pop with gdk_error_trap_pop_ignored().
+ * If you need the error code, use gdk_error_trap_pop() which may have
+ * to block and wait for the error to arrive from the X server.
+ *
+ * This API exists on all platforms but only does anything on X.
+ *
+ * You can use gdk_x11_display_error_trap_push() to ignore errors
+ * on only a single display.
+ *
+ * <example>
+ * <title>Trapping an X error</title>
+ * <programlisting>
+ * gdk_error_trap_push (<!-- -->);
+ *
+ *  // ... Call the X function which may cause an error here ...
+ *
+ *
+ * if (gdk_error_trap_pop (<!-- -->))
+ *  {
+ *    // ... Handle the error here ...
+ *  }
+ * </programlisting>
+ * </example>
+ *
+ */
+void
+gdk_error_trap_push (void)
+{
+  GdkGlobalErrorTrap *trap;
+  GdkDisplayManager *manager;
+  GSList *tmp_list;
+
+  trap = g_slice_new (GdkGlobalErrorTrap);
+  manager = gdk_display_manager_get ();
+  trap->displays = gdk_display_manager_list_displays (manager);
+
+  g_slist_foreach (trap->displays, (GFunc) g_object_ref, NULL);
+  for (tmp_list = trap->displays;
+       tmp_list != NULL;
+       tmp_list = tmp_list->next)
+    {
+      gdk_x11_display_error_trap_push (tmp_list->data);
+    }
 
   g_queue_push_head (&gdk_error_traps, trap);
-  _gdk_error_code = 0;
-  _gdk_error_warnings = 0;
 }
 
-gint
-gdk_error_trap_pop (void)
+static gint
+gdk_error_trap_pop_internal (gboolean need_code)
 {
-  GdkErrorTrap *trap;
+  GdkGlobalErrorTrap *trap;
   gint result;
+  GSList *tmp_list;
 
   trap = g_queue_pop_head (&gdk_error_traps);
 
-  g_return_val_if_fail (trap != NULL, 0);
+  g_return_val_if_fail (trap != NULL, Success);
+
+  result = Success;
+  for (tmp_list = trap->displays;
+       tmp_list != NULL;
+       tmp_list = tmp_list->next)
+    {
+      gint code = Success;
+
+      if (need_code)
+        code = gdk_x11_display_error_trap_pop (tmp_list->data);
+      else
+        gdk_x11_display_error_trap_pop_ignored (tmp_list->data);
 
-  result = _gdk_error_code;
+      /* we use the error on the last display listed, why not. */
+      if (code != Success)
+        result = code;
+    }
 
-  _gdk_error_code = trap->error_code;
-  _gdk_error_warnings = trap->error_warnings;
-  XSetErrorHandler (trap->old_handler);
+  g_slist_foreach (trap->displays, (GFunc) g_object_unref, NULL);
+  g_slist_free (trap->displays);
 
-  g_slice_free (GdkErrorTrap, trap);
+  g_slice_free (GdkGlobalErrorTrap, trap);
 
   return result;
 }
 
+/**
+ * gdk_error_trap_pop_ignored:
+ *
+ * Removes an error trap pushed with gdk_error_trap_push(), but
+ * without bothering to wait and see whether an error occurred.  If an
+ * error arrives later asynchronously that was triggered while the
+ * trap was pushed, that error will be ignored.
+ *
+ * Since: 3.0
+ */
+void
+gdk_error_trap_pop_ignored (void)
+{
+  gdk_error_trap_pop_internal (FALSE);
+}
+
+/**
+ * gdk_error_trap_pop:
+ *
+ * Removes an error trap pushed with gdk_error_trap_push().
+ * May block until an error has been definitively received
+ * or not received from the X server. gdk_error_trap_pop_ignored()
+ * is preferred if you don't need to know whether an error
+ * occurred, because it never has to block. If you don't
+ * need the return value of gdk_error_trap_pop(), use
+ * gdk_error_trap_pop_ignored().
+ *
+ * Prior to GDK 3.0, this function would not automatically
+ * sync for you, so you had to gdk_flush() if your last
+ * call to Xlib was not a blocking round trip.
+ *
+ * Return value: X error code or 0 on success
+ */
+gint
+gdk_error_trap_pop (void)
+{
+  return gdk_error_trap_pop_internal (TRUE);
+}
+
 gchar *
 gdk_get_display (void)
 {
index 70693b4dee9dc42ab93319b08260980e8efc0009..a4066e8f13218341e0b7b554059e7c68cac2fa8f 100644 (file)
@@ -60,6 +60,8 @@ struct _GdkVisualPrivate
   GdkScreen *screen;
 };
 
+void _gdk_x11_error_handler_push (void);
+void _gdk_x11_error_handler_pop  (void);
 
 void _gdk_xid_table_insert (GdkDisplay *display,
                            XID        *xid,
index ec6ddd582403508a669baaf080373ffa17ce2117..074ec5fb2056dcc49090f6ba58270b56c29da82b 100644 (file)
@@ -164,6 +164,12 @@ G_CONST_RETURN gchar *gdk_x11_get_xatom_name    (Atom         xatom);
 
 void       gdk_x11_display_grab              (GdkDisplay *display);
 void       gdk_x11_display_ungrab            (GdkDisplay *display);
+
+void                           gdk_x11_display_error_trap_push        (GdkDisplay *display);
+/* warn unused because you could use pop_ignored otherwise */
+G_GNUC_WARN_UNUSED_RESULT gint gdk_x11_display_error_trap_pop         (GdkDisplay *display);
+void                           gdk_x11_display_error_trap_pop_ignored (GdkDisplay *display);
+
 void        gdk_x11_register_standard_event_type (GdkDisplay *display,
                                                  gint        event_base,
                                                  gint        n_events);